home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Palettes / MiscTableScroll / MiscTableScroll.M < prev    next >
Text File  |  1996-02-11  |  65KB  |  2,012 lines

  1. //=============================================================================
  2. //
  3. //        Copyright (C) 1995, 1996 by Paul S. McCarthy and Eric Sunshine.
  4. //                Written by Paul S. McCarthy and Eric Sunshine.
  5. //                            All Rights Reserved.
  6. //
  7. //        This notice may not be removed from this source code.
  8. //
  9. //        This object is included in the MiscKit by permission from the authors
  10. //        and its use is governed by the MiscKit license, found in the file
  11. //        "License.rtf" in the MiscKit distribution.    Please refer to that file
  12. //        for a list of all applicable permissions and restrictions.
  13. //
  14. //=============================================================================
  15. //-----------------------------------------------------------------------------
  16. // MiscTableScroll.M
  17. //
  18. //        ScrollView class that displays a 2-D table of cells.
  19. //
  20. //-----------------------------------------------------------------------------
  21. //-----------------------------------------------------------------------------
  22. // $Id: MiscTableScroll.M,v 1.18 96/01/16 19:55:04 zarnuk Exp $
  23. // $Log:        MiscTableScroll.M,v $
  24. // Revision 1.18  96/01/16    19:55:04  zarnuk
  25. // Turns off display in -free.
  26. // Does not call -update after calling -setAutodisplay:
  27. // More careful about suppressing auto-sort after a drag.
  28. // 
  29. // Revision 1.17  96/01/13    23:33:54  zarnuk
  30. // Pulled-out sorting stuff into (Sort) category.
  31. // New version (1), since range of sortType values increased.
  32. // Plugged some memory leaks.
  33. // No longer tries to resort when "skip" slots are dragged.
  34. // 
  35. // Revision 1.16  95/12/19    23:16:38  sunshine
  36. // Fixed MiscTableBorder.cc:1107: failed assertion 
  37. // 
  38. // Revision 1.15  95/12/17    15:11:35  zarnuk
  39. // Added -border:sortSlot:, -sortCol:, -sortRow:.
  40. // 
  41. // Revision 1.14  95/10/20    00:12:40  sunshine
  42. // Was including MiscTableScroll.h and MiscTableCell.h with "" instead of <>.
  43. //-----------------------------------------------------------------------------
  44. #import <misckit/MiscTableScroll.h>
  45. #import <misckit/MiscTableCell.h>
  46. #import "MiscTableBorder.h"
  47. #import "MiscTableView.h"
  48. #import "MiscColView.h"
  49. #import "MiscRowView.h"
  50. #import "MiscNullView.h"
  51.  
  52. #import <new.h>
  53.  
  54. extern "Objective-C" {
  55. #import <appkit/Application.h>
  56. #import <appkit/Cell.h>
  57. #import <appkit/ClipView.h>
  58. #import <appkit/Font.h>
  59. #import <appkit/FontManager.h>
  60. }
  61.  
  62. extern "C" {
  63. #import <assert.h>
  64. #import <math.h>
  65. #import <strings.h>
  66. }
  67.  
  68. // There are no structural differences between versions 0 and 1.  However,
  69. // the range of the MiscSortType values increased from 0..8 to 0..12
  70. #define MISC_TS_VERSION_0        0
  71. #define MISC_TS_VERSION_1        1
  72. #define MISC_TS_VERSION            MISC_TS_VERSION_1
  73.  
  74. @implementation MiscTableScroll
  75.  
  76. //-----------------------------------------------------------------------------
  77. // + initialize
  78. //-----------------------------------------------------------------------------
  79. + initialize
  80.     {
  81.     if (self == [MiscTableScroll class])
  82.         {
  83.         [self setVersion: MISC_TS_VERSION];
  84.         }
  85.     return self;
  86.     }
  87.  
  88.  
  89. //-----------------------------------------------------------------------------
  90. // Tag Stuff
  91. //-----------------------------------------------------------------------------
  92. - (int) tag                { return tag; }
  93. - setTag:(int) x        { tag = x;    return self; }
  94.  
  95.  
  96. //-----------------------------------------------------------------------------
  97. // -nextText
  98. //-----------------------------------------------------------------------------
  99. - nextText                { return nextText; }
  100. - previousText            { return previousText; }
  101. - setNextText:obj
  102.     {
  103.     nextText = obj;
  104.     if (obj && [obj respondsTo: @selector(setPreviousText:)])
  105.         [obj setPreviousText: self];
  106.     return self;
  107.     }
  108. - setPreviousText:obj                    { previousText = obj; return self; }
  109. - (BOOL) isSelectable                    { return YES; }
  110. - (BOOL) isEnabled                        { return enabled; }
  111. - setEnabled:(BOOL)flag                    { enabled = flag; return self; }
  112.  
  113. - selectText:sender
  114.     {
  115.     if ([window firstResponder] != (id)tableView)
  116.         [window makeFirstResponder:tableView];
  117.     return self;
  118.     }
  119.  
  120.  
  121. //-----------------------------------------------------------------------------
  122. // Multicast Messages
  123. //-----------------------------------------------------------------------------
  124. - sendAction:(SEL)aSel to:obj forAllCells:(BOOL)flag
  125.         {
  126.         int const rlim = num_rows;
  127.         int const clim = num_cols;
  128.         for (int r = 0;     r < rlim;    r++)
  129.             for (int c = 0;     c < clim;    c++)
  130.                 if (flag || [self cellIsSelected:r:c])
  131.                     if (![obj perform:aSel with:[self cellAt:r:c]])
  132.                         return self;
  133.         return self;
  134.         }
  135.  
  136. - (int) makeCellsPerform:(SEL)aSel with:p1 with:p2 selectedOnly:(BOOL)flag
  137.         {
  138.         int count = 0;
  139.         int const rlim = num_rows;
  140.         int const clim = num_cols;
  141.         for (int r = 0;     r < rlim;    r++)
  142.             for (int c = 0;     c < clim;    c++)
  143.                 if (!flag || [self cellIsSelected:r:c])
  144.                     {
  145.                     id cell = [self cellAt:r:c];
  146.                     if ([cell respondsTo:aSel])
  147.                         if ([cell perform:aSel with:p1 with:p2])
  148.                             count++;
  149.                         else
  150.                             return count;
  151.                     }
  152.         return count;
  153.         }
  154.  
  155. - (int) makeCellsPerform:(SEL)aSel with:p1 selectedOnly:(BOOL)flag
  156.     { return [self makeCellsPerform:aSel with:p1 with:0 selectedOnly:flag]; }
  157. - (int) makeCellsPerform:(SEL)aSel selectedOnly:(BOOL)flag
  158.     { return [self makeCellsPerform:aSel with:0 with:0 selectedOnly:flag]; }
  159.  
  160. - (int) makeCellsPerform:(SEL)aSel
  161.     { return [self makeCellsPerform:aSel selectedOnly:NO]; }
  162. - (int) makeCellsPerform:(SEL)aSel with:p1
  163.     { return [self makeCellsPerform:aSel with:p1 selectedOnly:NO]; }
  164. - (int) makeCellsPerform:(SEL)aSel with:p1 with:p2
  165.     { return [self makeCellsPerform:aSel with:p1 with:p2 selectedOnly:NO];}
  166.  
  167.  
  168. //-----------------------------------------------------------------------------
  169. // FINDING CELLS
  170. //-----------------------------------------------------------------------------
  171.  
  172. - (int) border:(MiscBorderType)b findSlotWithTag:(int)x
  173.         {
  174.         int const lim = (int) [self numSlots:b];
  175.         for (int i = 0;     i < lim;  i++)
  176.             if ([self border:b slotTag:i] == x)
  177.                 return i;
  178.         return -1;
  179.         }
  180. - (int) findColWithTag:(int)x
  181.         { return [self border:MISC_COL_BORDER findSlotWithTag:x]; }
  182. - (int) findRowWithTag:(int)x
  183.         { return [self border:MISC_ROW_BORDER findSlotWithTag:x]; }
  184.  
  185.  
  186. - findCell:cell row:(int*)row col:(int*)col
  187.     {
  188.     int const NRows = [self numRows];
  189.     int const NCols = [self numCols];
  190.     for (int r = 0;     r < NRows;     r++)
  191.         for (int c = 0;     c < NCols;     c++)
  192.             if ([self cellAt:r:c] == cell)
  193.                 {
  194.                 *row = r;
  195.                 *col = c;
  196.                 return self;
  197.                 }
  198.     *row = -1;
  199.     *col = -1;
  200.     return 0;
  201.     }
  202.  
  203. - findCellWithTag:(int)x row:(int*)row col:(int*)col
  204.     {
  205.     int const NRows = [self numRows];
  206.     int const NCols = [self numCols];
  207.     for (int r = 0;     r < NRows;     r++)
  208.         for (int c = 0;     c < NCols;     c++)
  209.             {
  210.             id const cell = [self cellAt:r:c];
  211.             if (cell && [cell respondsTo:@selector(tag)] && [cell tag] == x)
  212.                 {
  213.                 *row = r;
  214.                 *col = c;
  215.                 return cell;
  216.                 }
  217.             }
  218.     *row = -1;
  219.     *col = -1;
  220.     return 0;
  221.     }
  222.  
  223. - findCellWithTag:(int)x
  224.     {
  225.     int r, c;
  226.     return [self findCellWithTag:x row:&r col:&c];
  227.     }
  228.  
  229.  
  230.  
  231.  
  232. //-----------------------------------------------------------------------------
  233. // Selection stuff
  234. //-----------------------------------------------------------------------------
  235. - (MiscSelectionMode) selectionMode { return mode; }
  236. - (void) setSelectionMode:(MiscSelectionMode) x
  237.     {
  238.     if (x != mode)
  239.         {
  240.         mode = x;
  241.         [colInfo.view setSelectionMode: mode];
  242.         [rowInfo.view setSelectionMode: mode];
  243.         [tableView setSelectionMode: mode];
  244.         }
  245.     }
  246.  
  247. - selectedCell { return 0; }    // FIXME: write this
  248.  
  249. - (BOOL) borderHasSelection: (MiscBorderType)b
  250.         { return info[b]->border->hasSelection(); }
  251. - (BOOL) hasRowSelection { return [self borderHasSelection:MISC_ROW_BORDER]; }
  252. - (BOOL) hasColSelection { return [self borderHasSelection:MISC_COL_BORDER]; }
  253.  
  254. - (BOOL) borderHasMultipleSelection: (MiscBorderType)b
  255.         { return info[b]->border->hasMultipleSelection(); }
  256. - (BOOL) hasMultipleRowSelection
  257.         { return [self borderHasMultipleSelection: MISC_ROW_BORDER]; }
  258. - (BOOL) hasMultipleColSelection
  259.         { return [self borderHasMultipleSelection: MISC_COL_BORDER]; }
  260.  
  261. - (unsigned int) borderNumSelectedSlots: (MiscBorderType)b
  262.         { return info[b]->border->numSelected(); }
  263. - (unsigned int) numSelectedRows
  264.         { return [self borderNumSelectedSlots: MISC_ROW_BORDER]; }
  265. - (unsigned int) numSelectedCols
  266.         { return [self borderNumSelectedSlots: MISC_COL_BORDER]; }
  267.  
  268. - (BOOL) border: (MiscBorderType)b slotIsSelected:(MiscCoord_P)slot
  269.         { return info[b]->border->slotIsSelected( slot ); }
  270. - (BOOL) rowIsSelected:(MiscCoord_P)row
  271.         { return [self border:MISC_ROW_BORDER slotIsSelected:row]; }
  272. - (BOOL) colIsSelected:(MiscCoord_P)col
  273.         { return [self border:MISC_COL_BORDER slotIsSelected:col]; }
  274. - (BOOL) cellIsSelected:(MiscCoord_P)r :(MiscCoord_P)c
  275.         { return ([self rowIsSelected:r] || [self colIsSelected:c]); }
  276.  
  277. - (MiscCoord_P) borderSelectedSlot: (MiscBorderType)b
  278.         { return info[b]->border->selectedSlot(); }
  279. - (MiscCoord_P) selectedRow
  280.         { return [self borderSelectedSlot:MISC_ROW_BORDER]; }
  281. - (MiscCoord_P) selectedCol
  282.         { return [self borderSelectedSlot:MISC_COL_BORDER]; }
  283.  
  284. - (void) border: (MiscBorderType)b selectedTags: (MiscIntList*)tags
  285.         { info[b]->border->selectedTags( tags ); }
  286. - (void) selectedRowTags: (MiscIntList*) tags
  287.         { [self border:MISC_ROW_BORDER selectedTags:tags]; }
  288. - (void) selectedColTags: (MiscIntList*) tags
  289.         { [self border:MISC_COL_BORDER selectedTags:tags]; }
  290.  
  291. - (void) border: (MiscBorderType)b selectedSlots: (MiscIntList*)slots
  292.         { info[b]->border->selectedSlots( slots ); }
  293. - (void) selectedRows: (MiscIntList*) rows
  294.         { [self border:MISC_ROW_BORDER selectedSlots:rows]; }
  295. - (void) selectedCols: (MiscIntList*) cols
  296.         { [self border:MISC_COL_BORDER selectedSlots:cols]; }
  297.  
  298. - (void) selectionChanged
  299.         {
  300.         if ([self isAutodisplay] && [self canDraw])
  301.             [self reflectSelection];
  302.         else
  303.             [self setNeedsDisplay:YES];
  304.         }
  305.  
  306. - (void) border: (MiscBorderType)b selectSlot:(MiscCoord_P)slot
  307.         {
  308.         BOOL changed = NO;
  309.         MiscTableBorder* const bp = info[b]->border;
  310.         unsigned int const n = bp->numSelected();
  311.         if (0 <= slot && slot < bp->count())
  312.             {
  313.             if (n != 1 || bp->selectedSlot() != slot)
  314.                 {
  315.                 bp->selectSlot( slot );
  316.                 changed = YES;
  317.                 }
  318.             }
  319.         else
  320.             {
  321.             if (n > 0)
  322.                 {
  323.                 bp->selectNone();
  324.                 changed = YES;
  325.                 }
  326.             }
  327.         if (changed)
  328.             [self selectionChanged];
  329.         }
  330. - (void) selectRow:(MiscCoord_P)row
  331.         { [self border:MISC_ROW_BORDER selectSlot:row]; }
  332. - (void) selectCol:(MiscCoord_P)col
  333.         { [self border:MISC_COL_BORDER selectSlot:col]; }
  334.  
  335. - (void) border: (MiscBorderType)b selectTags: (MiscIntList*)tags
  336.         {
  337.         info[b]->border->selectTags( tags );
  338.         [self selectionChanged];
  339.         }
  340. - (void) selectRowTags: (MiscIntList*) tags
  341.         { [self border:MISC_ROW_BORDER selectTags:tags]; }
  342. - (void) selectColTags: (MiscIntList*) tags
  343.         { [self border:MISC_COL_BORDER selectTags:tags]; }
  344.  
  345. - (void) border: (MiscBorderType)b selectSlots: (MiscIntList*)slots
  346.         {
  347.         info[b]->border->selectSlots( slots );
  348.         [self selectionChanged];
  349.         }
  350. - (void) selectRows: (MiscIntList*) rows
  351.         { [self border:MISC_ROW_BORDER selectSlots:rows]; }
  352. - (void) selectCols: (MiscIntList*) cols;
  353.         { [self border:MISC_COL_BORDER selectSlots:cols]; }
  354.  
  355. - (void) borderSelectAll: (MiscBorderType)b
  356.         {
  357.         if (mode == MISC_LIST_MODE || mode == MISC_HIGHLIGHT_MODE)
  358.             {
  359.             info[b]->border->selectAll();
  360.             [self selectionChanged];
  361.             }
  362.         }
  363. - (void) selectAllRows { [self borderSelectAll: MISC_ROW_BORDER]; }
  364. - (void) selectAllCols { [self borderSelectAll: MISC_COL_BORDER]; }
  365. - selectAll:sender
  366.         {
  367.         [self selectAllRows];
  368.         [self sendActionIfEnabled];
  369.         return self;
  370.         }
  371.  
  372. - (void) borderClearSelection: (MiscBorderType)b
  373.         {
  374.         info[b]->border->selectNone();
  375.         [self selectionChanged];
  376.         }
  377. - (void) clearRowSelection { [self borderClearSelection: MISC_ROW_BORDER]; }
  378. - (void) clearColSelection { [self borderClearSelection: MISC_COL_BORDER]; }
  379. - (void) clearSelection { [self clearRowSelection]; [self clearColSelection]; }
  380.  
  381.  
  382. //-----------------------------------------------------------------------------
  383. // Keyboard cursor stuff
  384. //-----------------------------------------------------------------------------
  385. - (void) reflectCursor { [tableView reflectCursor]; }
  386. - (MiscCoord_P) borderCursor: (MiscBorderType)b
  387.         { return info[b]->border->getCursor_P(); }
  388. - (MiscCoord_P) cursorRow { return [self borderCursor: MISC_ROW_BORDER]; }
  389. - (MiscCoord_P) cursorCol { return [self borderCursor: MISC_COL_BORDER]; }
  390.  
  391. - (void) border: (MiscBorderType)b setCursor: (MiscCoord_P) slot
  392.         { info[b]->border->setCursor_P( slot ); [self reflectCursor]; }
  393. - (void) setCursorRow: (MiscCoord_P) row
  394.         { [self border: MISC_ROW_BORDER setCursor: row]; }
  395. - (void) setCursorCol: (MiscCoord_P) col
  396.         { [self border: MISC_COL_BORDER setCursor: col]; }
  397.  
  398. - (void) borderClearCursor: (MiscBorderType)b
  399.         { info[b]->border->clearCursor(); [self reflectCursor]; }
  400. - (void) clearCursorRow { [self borderClearCursor: MISC_ROW_BORDER]; }
  401. - (void) clearCursorCol { [self borderClearCursor: MISC_COL_BORDER]; }
  402. - (void) clearCursor { [self clearCursorRow]; [self clearCursorCol]; }
  403.  
  404. - (BOOL) borderHasValidCursor: (MiscBorderType)b
  405.         { return info[b]->border->hasValidCursor(); }
  406. - (BOOL) hasValidCursorRow
  407.         { return [self borderHasValidCursor: MISC_ROW_BORDER]; }
  408. - (BOOL) hasValidCursorCol
  409.         { return [self borderHasValidCursor: MISC_COL_BORDER]; }
  410.  
  411.  
  412. //-----------------------------------------------------------------------------
  413. // Overrides...     Scrollers are always required.
  414. //-----------------------------------------------------------------------------
  415. - setHorizScrollerRequired: (BOOL) flag { return self; }
  416. - setVertScrollerRequired: (BOOL) flag    { return self; }
  417.  
  418.  
  419. //-----------------------------------------------------------------------------
  420. // - getDocClipFrame:
  421. //-----------------------------------------------------------------------------
  422. - (void) getDocClipFrame: (NXRect*) rect
  423.     {
  424.     [contentView getFrame: rect];
  425.     }
  426.  
  427.  
  428. //-----------------------------------------------------------------------------
  429. // - freeBorder:
  430. //-----------------------------------------------------------------------------
  431. - (void) freeBorder:(MiscBorderInfo*)p
  432.     {
  433.     [p->view removeFromSuperview];
  434.     [p->view free];
  435.     [p->clip removeFromSuperview];
  436.     [p->clip free];
  437.     delete p->border;
  438.     }
  439.  
  440.  
  441. //-----------------------------------------------------------------------------
  442. // - free
  443. //-----------------------------------------------------------------------------
  444. - free
  445.     {
  446.     [self setAutodisplay:NO];            // Don't do any drawing!
  447.     [self emptyAndFreeCells];
  448.     [self freeBorder:&colInfo];
  449.     [self freeBorder:&rowInfo];
  450.     [nullView removeFromSuperview];
  451.     [nullView free];
  452.     [tableView removeFromSuperview];
  453.     [tableView free];
  454.     return [super free];
  455.     }
  456.  
  457.  
  458. //-----------------------------------------------------------------------------
  459. // get/set min/max total size limits.
  460. //-----------------------------------------------------------------------------
  461. - (NXCoord) totalSize:(MiscBorderType)b
  462.         { return (NXCoord) info[b]->border->totalSize(); }
  463. - (NXCoord) totalWidth
  464.         { return [self totalSize:MISC_COL_BORDER]; }
  465. - (NXCoord) totalHeight
  466.         { return [self totalSize:MISC_ROW_BORDER]; }
  467.  
  468. - (NXCoord) minTotalSize:(MiscBorderType)b
  469.         { return (NXCoord) info[b]->border->getMinTotalSize(); }
  470. - (NXCoord) maxTotalSize:(MiscBorderType)b
  471.         { return (NXCoord) info[b]->border->getMaxTotalSize(); }
  472. - (NXCoord) minTotalWidth
  473.         { return [self minTotalSize:MISC_COL_BORDER]; }
  474. - (NXCoord) maxTotalWidth
  475.         { return [self maxTotalSize:MISC_COL_BORDER]; }
  476. - (NXCoord) minTotalHeight
  477.         { return [self minTotalSize:MISC_ROW_BORDER]; }
  478. - (NXCoord) maxTotalHeight
  479.         { return [self maxTotalSize:MISC_ROW_BORDER]; }
  480.  
  481. // FIXME: Need to decide whether or not to update the views here.
  482. // FIXME: Should check current value before setting.
  483. - (void) border:(MiscBorderType)b setMinTotalSize:(NXCoord)size
  484.         { info[b]->border->setMinTotalSize( (MiscPixels)floor(size) ); }
  485. - (void) border:(MiscBorderType)b setMaxTotalSize:(NXCoord)size
  486.         { info[b]->border->setMaxTotalSize( (MiscPixels)floor(size) ); }
  487. - (void) setMinTotalWidth:(NXCoord)size
  488.         { [self border:MISC_COL_BORDER setMinTotalSize:size]; }
  489. - (void) setMaxTotalWidth:(NXCoord)size
  490.         { [self border:MISC_COL_BORDER setMaxTotalSize:size]; }
  491. - (void) setMinTotalHeight:(NXCoord)size
  492.         { [self border:MISC_ROW_BORDER setMinTotalSize:size]; }
  493. - (void) setMaxTotalHeight:(NXCoord)size
  494.         { [self border:MISC_ROW_BORDER setMaxTotalSize:size]; }
  495.  
  496.  
  497. //-----------------------------------------------------------------------------
  498. // - constrainSize
  499. //-----------------------------------------------------------------------------
  500. - (void) constrainSize
  501.     {
  502.     NXRect r;
  503.     [self getDocClipFrame: &r];
  504.     if ([self minTotalSizeIsConstrained:MISC_COL_BORDER])
  505.         [self border:MISC_COL_BORDER setMinTotalSize: r.size.width];
  506.     if ([self maxTotalSizeIsConstrained:MISC_COL_BORDER])
  507.         [self border:MISC_COL_BORDER setMaxTotalSize: r.size.width];
  508.     if ([self minTotalSizeIsConstrained:MISC_ROW_BORDER])
  509.         [self border:MISC_ROW_BORDER setMinTotalSize: r.size.height];
  510.     if ([self maxTotalSizeIsConstrained:MISC_ROW_BORDER])
  511.         [self border:MISC_ROW_BORDER setMaxTotalSize: r.size.height];
  512.     [rowInfo.view adjustSize];
  513.     [colInfo.view adjustSize];
  514.     [tableView adjustSize];
  515.     }
  516.  
  517.  
  518. //-----------------------------------------------------------------------------
  519. // - sizeToCells
  520. //-----------------------------------------------------------------------------
  521. - sizeToCells
  522.     {
  523.     [self constrainSize];
  524.     return self;
  525.     }
  526.  
  527.  
  528. //-----------------------------------------------------------------------------
  529. // get/set min/max constrained
  530. //-----------------------------------------------------------------------------
  531. - (BOOL) minTotalSizeIsConstrained:(MiscBorderType)b
  532.         { return info[b]->constrain_min; }
  533. - (BOOL) maxTotalSizeIsConstrained:(MiscBorderType)b
  534.         { return info[b]->constrain_max; }
  535. - (BOOL) minTotalWidthIsConstrained
  536.         { return [self minTotalSizeIsConstrained:MISC_COL_BORDER]; }
  537. - (BOOL) maxTotalWidthIsConstrained
  538.         { return [self maxTotalSizeIsConstrained:MISC_COL_BORDER]; }
  539. - (BOOL) minTotalHeightIsConstrained
  540.         { return [self minTotalSizeIsConstrained:MISC_ROW_BORDER]; }
  541. - (BOOL) maxTotalHeightIsConstrained
  542.         { return [self maxTotalSizeIsConstrained:MISC_ROW_BORDER]; }
  543.  
  544. - (void) border:(MiscBorderType)b constrainMinTotalSize:(BOOL)flag;
  545.         {
  546.         MiscBorderInfo* ip = info[b];
  547.         if (ip->constrain_min != flag)
  548.             {
  549.             ip->constrain_min = flag;
  550.             if (!flag)
  551.                 [self border:MISC_COL_BORDER setMinTotalSize:0];
  552.             [self constrainSize];
  553.             }
  554.         }
  555.  
  556. - (void) border:(MiscBorderType)b constrainMaxTotalSize:(BOOL)flag
  557.         {
  558.         MiscBorderInfo* ip = info[b];
  559.         if (ip->constrain_max != flag)
  560.             {
  561.             ip->constrain_max = flag;
  562.             if (!flag)
  563.                 [self border:MISC_COL_BORDER
  564.                         setMaxTotalSize: (NXCoord) MISC_MAX_PIXELS_SIZE ];
  565.             [self constrainSize];
  566.             }
  567.         }
  568.  
  569. - (void) constrainMinTotalWidth:(BOOL)flag
  570.         { [self border:MISC_COL_BORDER constrainMinTotalSize:flag]; }
  571. - (void) constrainMaxTotalWidth:(BOOL)flag
  572.         { [self border:MISC_COL_BORDER constrainMaxTotalSize:flag]; }
  573. - (void) constrainMinTotalHeight:(BOOL)flag
  574.         { [self border:MISC_ROW_BORDER constrainMinTotalSize:flag]; }
  575. - (void) constrainMaxTotalHeight:(BOOL)flag
  576.         { [self border:MISC_ROW_BORDER constrainMaxTotalSize:flag]; }
  577.  
  578.  
  579. //-----------------------------------------------------------------------------
  580. // - sizeTo::
  581. //-----------------------------------------------------------------------------
  582. - sizeTo:(NXCoord)width :(NXCoord)height
  583.     {
  584.     [super sizeTo:width:height];
  585.     [self constrainSize];
  586.     return self;
  587.     }
  588.  
  589.  
  590. //-----------------------------------------------------------------------------
  591. // - forwardBGColor
  592. //-----------------------------------------------------------------------------
  593. - (void) forwardBGColor
  594.     {
  595.     [super setBackgroundColor: backgroundColor];
  596.     [colInfo.clip setBackgroundColor: backgroundColor];
  597.     [rowInfo.clip setBackgroundColor: backgroundColor];
  598.     }
  599.  
  600.  
  601. //-----------------------------------------------------------------------------
  602. // - initBorder:type:
  603. //-----------------------------------------------------------------------------
  604. - (void) initBorder:(MiscBorderInfo*) p type:(MiscBorderType) type
  605.     {
  606.     NXZone* const z = [self zone];
  607.     if (p->border == 0)
  608.         p->border = new( NXZoneMalloc(z,sizeof(*(p->border))) )
  609.                         MiscTableBorder( type );
  610.     p->border->setOwner( self );
  611.  
  612.     if (type == MISC_COL_BORDER)
  613.         p->view = [[MiscColView allocFromZone:z] 
  614.                         initFrame:0 scroll:self info:p->border];
  615.     else
  616.         p->view = [[MiscRowView allocFromZone:z]
  617.                         initFrame:0 scroll:self info:p->border];
  618.  
  619.     p->clip = [[ClipView allocFromZone:z] initFrame:0];
  620.     [p->clip setDocView:p->view];
  621.     if (p->isOn)
  622.         {
  623.         [self addSubview: p->clip];
  624.         [window invalidateCursorRectsForView: p->view];
  625.         }
  626.     }
  627.  
  628.  
  629. //-----------------------------------------------------------------------------
  630. // - doInit:
  631. //
  632. //        NOTE *1*: The tableView was initialized with an argument of 0 so it's
  633. //                frame is invalid.  Calling constrainSize with an invalid frame
  634. //                can result in crashers when it tries to access slots outside
  635. //                of the appropriate area.  Calling -tile first ensures that the
  636. //                frame is valid.
  637. //-----------------------------------------------------------------------------
  638. - (void) doInit:(int)ver
  639.     {
  640.     [window disableDisplay];
  641.     [self setBorderType: NX_BEZEL];
  642.     [super setHorizScrollerRequired: YES];
  643.     [super setVertScrollerRequired: YES];
  644.  
  645.     info[ MISC_COL_BORDER ] = &colInfo;
  646.     info[ MISC_ROW_BORDER ] = &rowInfo;
  647.  
  648.     [self initBorder:&colInfo type:MISC_COL_BORDER];
  649.     [self initBorder:&rowInfo type:MISC_ROW_BORDER];
  650.  
  651.     NXZone* const z = [self zone];
  652.  
  653.     tableView = [[MiscTableView allocFromZone:z] initFrame:0
  654.         scroll:self
  655.         colInfo:colInfo.border
  656.         rowInfo:rowInfo.border];
  657.  
  658.     nullView = [[MiscNullView allocFromZone:z] initFrame:0];
  659.  
  660.     if (colInfo.isOn && rowInfo.isOn)
  661.         [self addSubview:nullView];
  662.  
  663.     id oldView = [self setDocView: tableView];
  664.     [oldView free];
  665.     [self tile];                                        // NOTE *1*
  666.     [self constrainSize];
  667.     [self forwardBGColor];
  668.  
  669.     [self registerServicesTypes];
  670.     [window reenableDisplay];
  671.     }
  672.  
  673.  
  674. //-----------------------------------------------------------------------------
  675. // - initFrame:
  676. //-----------------------------------------------------------------------------
  677. - initFrame: (NXRect const*) frameRect
  678.     {
  679.     [super initFrame: frameRect];
  680.     font = [[self class] defaultFont];
  681.     tag = 0;
  682.     enabled = YES;
  683.     colInfo.border = 0; colInfo.isOn = YES;
  684.     colInfo.constrain_min = YES;
  685.     colInfo.constrain_max = NO;
  686.     rowInfo.border = 0; rowInfo.isOn = NO;
  687.     rowInfo.constrain_min = YES;
  688.     rowInfo.constrain_max = NO;
  689.     textColor = [[self class] defaultTextColor];
  690.     backgroundColor = [[self class] defaultBackgroundColor];
  691.     highlightTextColor = [[self class] defaultHighlightTextColor];
  692.     highlightBackgroundColor = [[self class] defaultHighlightBackgroundColor];
  693.  
  694.     [self doInit:MISC_TS_VERSION];
  695.  
  696.     if ([self respondsTo:@selector(initIB)]) [self perform:@selector(initIB)];
  697.     return self;
  698.     }
  699.  
  700.  
  701. //-----------------------------------------------------------------------------
  702. // - setFrame:
  703. //-----------------------------------------------------------------------------
  704. - setFrame: (NXRect const*) frameRect
  705.     {
  706.     [super setFrame:frameRect];
  707.     [self constrainSize];
  708.     return self;
  709.     }
  710.  
  711.  
  712. //-----------------------------------------------------------------------------
  713. // - adjustSizes
  714. //-----------------------------------------------------------------------------
  715. - (void) adjustSizes
  716.     {
  717.     if (colInfo.isOn && colInfo.view != 0)
  718.         [colInfo.view adjustSize];
  719.     if (rowInfo.isOn && rowInfo.view != 0)
  720.         [rowInfo.view adjustSize];
  721.     [tableView adjustSize];
  722.     }
  723.  
  724.  
  725. //-----------------------------------------------------------------------------
  726. // - tile
  727. //-----------------------------------------------------------------------------
  728. - tile
  729.     {
  730.     [window disableDisplay];
  731.     [super tile];
  732.     [self adjustSizes];
  733.  
  734.     if (colInfo.isOn && !rowInfo.isOn)
  735.         {
  736.         NXCoord colHeight = [colInfo.view frameHeight];
  737.         NXRect colRect;
  738.         NXRect docRect;
  739.  
  740.         [contentView getFrame: &docRect];
  741.  
  742.         NXDivideRect( &docRect, &colRect, colHeight, NX_YMIN );
  743.  
  744.         [colInfo.clip setFrame: &colRect];
  745.         [contentView setFrame: &docRect];
  746.         [window invalidateCursorRectsForView: colInfo.view];
  747.         }
  748.     else if (!colInfo.isOn && rowInfo.isOn)
  749.         {
  750.         NXCoord rowWidth  = [rowInfo.view frameHeight];
  751.         NXRect rowRect;
  752.         NXRect docRect;
  753.  
  754.         [contentView getFrame: &docRect];
  755.  
  756.         NXDivideRect( &docRect, &rowRect, rowWidth, NX_XMIN );
  757.  
  758.         [rowInfo.clip setFrame: &rowRect];
  759.         [contentView setFrame: &docRect];
  760.         [window invalidateCursorRectsForView: rowInfo.view];
  761.         }
  762.     else if (colInfo.isOn && rowInfo.isOn)
  763.         {
  764.         NXCoord colHeight = [colInfo.view frameHeight];
  765.         NXCoord rowWidth  = [rowInfo.view frameHeight];
  766.         NXRect nulRect;
  767.         NXRect colRect;
  768.         NXRect rowRect;
  769.         NXRect docRect;
  770.  
  771.         [contentView getFrame: &docRect];
  772.  
  773.         NXDivideRect( &docRect, &colRect, colHeight, NX_YMIN );
  774.         NXDivideRect( &colRect, &nulRect, rowWidth, NX_XMIN );
  775.         NXDivideRect( &docRect, &rowRect, rowWidth, NX_XMIN );
  776.  
  777.         [nullView setFrame: &nulRect];
  778.         [colInfo.clip setFrame: &colRect];
  779.         [rowInfo.clip setFrame: &rowRect];
  780.         [contentView setFrame: &docRect];
  781.         [window invalidateCursorRectsForView: colInfo.view];
  782.         [window invalidateCursorRectsForView: rowInfo.view];
  783.         }
  784.  
  785.     [window reenableDisplay];
  786.     return self;
  787.     }
  788.  
  789.  
  790. //-----------------------------------------------------------------------------
  791. // - reflectScroll:
  792. //-----------------------------------------------------------------------------
  793. - reflectScroll: aView
  794.     {
  795.     if (aView == contentView) // only reflect position of contentView
  796.         [super reflectScroll: aView];
  797.     return self;
  798.     }
  799.  
  800.  
  801. //-----------------------------------------------------------------------------
  802. // - scrollClip:to:
  803. //-----------------------------------------------------------------------------
  804. - scrollClip: aClipView to: (const NXPoint *) aPoint
  805.     {
  806.     if (aClipView == contentView)                // contentView only.
  807.         {
  808.         NXRect rect;
  809.         [window disableFlushWindow];
  810.  
  811.         [aClipView rawScroll: aPoint];            // Scroll content
  812.  
  813.         if (colInfo.isOn)
  814.             {
  815.             [colInfo.clip getBounds: &rect];    // Maybe scroll col headings.
  816.             if (rect.origin.x != aPoint->x)
  817.                 {
  818.                 rect.origin.x = aPoint->x;
  819.                 [colInfo.clip rawScroll: &rect.origin];
  820.                 [window invalidateCursorRectsForView: colInfo.view];
  821.                 }
  822.             }
  823.  
  824.         if (rowInfo.isOn)
  825.             {
  826.             [rowInfo.clip getBounds: &rect];    // Maybe scroll row labels.
  827.             if (rect.origin.y != aPoint->y)
  828.                 {
  829.                 rect.origin.y = aPoint->y;
  830.                 [rowInfo.clip rawScroll: &rect.origin];
  831.                 [window invalidateCursorRectsForView: rowInfo.view];
  832.                 }
  833.             }
  834.  
  835.         [[window reenableFlushWindow] flushWindow];
  836.         }
  837.     else if (aClipView == (id)colInfo.clip)
  838.         {
  839.         NXRect rect;
  840.         [contentView getBounds: &rect];
  841.         rect.origin.x = aPoint->x;
  842.         [self scrollClip:contentView to:&(rect.origin)];
  843.         [self reflectScroll:contentView];
  844.         }
  845.     else if (aClipView == (id)rowInfo.clip)
  846.         {
  847.         NXRect rect;
  848.         [contentView getBounds: &rect];
  849.         rect.origin.y = aPoint->y;
  850.         [self scrollClip:contentView to:&(rect.origin)];
  851.         [self reflectScroll:contentView];
  852.         }
  853.     return self;
  854.     }
  855.  
  856.  
  857.  
  858. //-----------------------------------------------------------------------------
  859. // Delegate Stuff
  860. //-----------------------------------------------------------------------------
  861. - delegate                        { return delegate; }
  862. - setDelegate:obj                { delegate = obj; return self; }
  863. - dataDelegate                    { return dataDelegate; }
  864. - setDataDelegate:obj            { dataDelegate = obj; return self; }
  865.  
  866. - (char const*) border:(MiscBorderType)b getDelegateSlotTitle:(int)slot
  867.     {
  868.     if (delegate != 0 &&
  869.         [delegate respondsTo:@selector(tableScroll:border:slotTitle:)])
  870.         return [delegate tableScroll:self border:b slotTitle:slot];
  871.  
  872.     if (dataDelegate != 0 &&
  873.         [dataDelegate respondsTo:@selector(tableScroll:border:slotTitle:)])
  874.         return [dataDelegate tableScroll:self border:b slotTitle:slot];
  875.  
  876.     return 0;
  877.     }
  878.  
  879. - border:(MiscBorderType)b getDelegateSlotPrototype:(int)s
  880.     {
  881.     if (delegate != 0 &&
  882.         [delegate respondsTo:@selector(tableScroll:border:slotPrototype:)])
  883.         return [delegate tableScroll:self border:b slotPrototype:s];
  884.  
  885.     if (dataDelegate != 0 &&
  886.         [dataDelegate respondsTo:@selector(tableScroll:border:slotPrototype:)])
  887.         return [dataDelegate tableScroll:self border:b slotPrototype:s];
  888.  
  889.     return 0;
  890.     }
  891.  
  892. - (void) border:(MiscBorderType)b slotDraggedFrom:(int)fromPos to:(int)toPos
  893.     {
  894.     MiscBorderType const ob = otherBorder(b);
  895.     if ([self autoSortSlots:ob])
  896.         {
  897.         int slot = [self border:b slotAtPosition:toPos];
  898.         if ([self border:b slotSortType:slot] != MISC_SORT_SKIP ||
  899.             [self border:b slotSortFunc:slot] != 0)
  900.             [self sortSlots:ob]; // Don't resort if it doesn't affect ordering.
  901.         }
  902.     if (delegate != 0 &&
  903.         [delegate respondsTo:@selector(tableScroll:border:slotDraggedFrom:to:)])
  904.         [delegate tableScroll:self border:b slotDraggedFrom:fromPos to:toPos];
  905.     }
  906.  
  907. - (void) border:(MiscBorderType)b slotResized:(int)n
  908.     {
  909.     if (delegate != 0 &&
  910.         [delegate respondsTo:@selector(tableScroll:border:slotResized:)])
  911.         [delegate tableScroll:self border:b slotResized:n];
  912.     }
  913.  
  914.  
  915. //-----------------------------------------------------------------------------
  916. // Target / Action
  917. //-----------------------------------------------------------------------------
  918. - target                        { return target; }
  919. - setTarget:obj                    { target = obj; return self; }
  920. - doubleTarget                    { return doubleTarget; }
  921. - setDoubleTarget:obj            { doubleTarget = obj; return self; }
  922. - (SEL) action                    { return action; }
  923. - setAction:(SEL)new_sel        { action = new_sel; return self; }
  924. - setDoubleAction:(SEL)new_sel    { doubleAction = new_sel; return self; }
  925. - (SEL) doubleAction            { return doubleAction; }
  926.  
  927. - sendAction:(SEL)aSel to:obj
  928.         {
  929.         if (aSel == 0)
  930.             aSel = action;
  931.         if (obj == 0)
  932.             obj = target;
  933.         return ([NXApp sendAction:aSel to:obj from:self] ? self : 0);
  934.         }
  935.  
  936. - (SEL) getCellAction:cell
  937.         {
  938.         if ([cell respondsTo:@selector(action)])
  939.             return [cell action];
  940.         return 0;
  941.         }
  942.  
  943. - getCellTarget:cell
  944.         {
  945.         if ([cell respondsTo:@selector(target)])
  946.             return [cell target];
  947.         return 0;
  948.         }
  949.  
  950. - sendAction
  951.         {
  952.         id cell = [self selectedCell];
  953.         return [self sendAction:[self getCellAction:cell]
  954.                                 to:[self getCellTarget:cell]];
  955.         }
  956.  
  957. - sendDoubleAction
  958.         {
  959.         return [self sendAction:doubleAction to:doubleTarget];
  960.         }
  961.  
  962. - sendActionIfEnabled
  963.         {
  964.         if ([self isEnabled])
  965.             return [self sendAction];
  966.         return 0;
  967.         }
  968.  
  969. - sendDoubleActionIfEnabled
  970.         {
  971.         if ([self isEnabled])
  972.             return [self sendDoubleAction];
  973.         return 0;
  974.         }
  975.  
  976.  
  977. //-----------------------------------------------------------------------------
  978. // FONT
  979. //-----------------------------------------------------------------------------
  980. + (Font*) defaultFont
  981.     {
  982.     return [Font userFontOfSize:12.0 matrix:NX_FLIPPEDMATRIX];
  983.     }
  984.  
  985. - font
  986.     {
  987.     return font;
  988.     }
  989.  
  990.  
  991. static double get_height( Font* font )
  992.     {
  993.     NXFontMetrics const* const p = [font metrics];
  994.     double const size = [font pointSize];
  995.     return ((p->fontBBox[3] - p->fontBBox[1]) * size);
  996.     }
  997.  
  998.  
  999. - setFont:newFont
  1000.     {
  1001.     if (newFont != 0 && newFont != (id)font && [newFont isKindOf:[Font class]])
  1002.         {
  1003.         [window disableDisplay];
  1004.         Font* oldFont = font;
  1005.         font = newFont;
  1006.         NXCoord old_size = [self uniformSizeRows];
  1007.         if (old_size != 0)
  1008.             {
  1009.             // FIXME: Handle this better.  Different cell-types will have
  1010.             // different amounts of "fixed-size" border stuff.
  1011.             NXCoord const BORDER_THICKNESS = 1;
  1012.             old_size -= BORDER_THICKNESS;
  1013.             NXCoord const new_size =
  1014.                 floor(    0.5 + (double(old_size) *
  1015.                         (get_height( newFont ) / get_height( oldFont ))));
  1016.             if (new_size != old_size)
  1017.                 [self setUniformSizeRows:(new_size + BORDER_THICKNESS)];
  1018.             }
  1019.         // FIXME: Set font in all existing prototype cells.
  1020.         // WARNING: Currently, just asking the border for a prototype
  1021.         // in a given slot allocates and initializes an array of prototypes.
  1022.         if (![self isLazy])                // Eager beaver sets all cells now.
  1023.             {
  1024.             int const NRows = num_rows;
  1025.             int const NCols = num_cols;
  1026.             for (int r = 0;     r < NRows;     r++)
  1027.                 {
  1028.                 for (int c = 0;     c < NCols;     c++)
  1029.                     {
  1030.                     id cell = [self cellAt:r:c];
  1031.                     if (cell != 0)
  1032.                         {
  1033.                         if ([cell respondsTo:@selector(setOwnerFont:)])
  1034.                             [cell setOwnerFont:newFont];
  1035.                         else if ([cell respondsTo:@selector(setFont:)])
  1036.                             [cell setFont:newFont];
  1037.                         }
  1038.                     }
  1039.                 }
  1040.             }
  1041.         if (delegate != 0 &&
  1042.             [delegate respondsTo:@selector(tableScroll:fontChangedFrom:to:)])
  1043.             [delegate tableScroll:self fontChangedFrom:oldFont to:newFont];
  1044.         if (dataDelegate != 0 &&
  1045.             [dataDelegate respondsTo:
  1046.                         @selector(tableScroll:fontChangedFrom:to:)])
  1047.             [dataDelegate tableScroll:self fontChangedFrom:oldFont to:newFont];
  1048.  
  1049.         [window reenableDisplay];
  1050.         [self update];
  1051.         }
  1052.     return self;
  1053.     }
  1054.  
  1055.  
  1056. - changeFont:sender
  1057.     {
  1058.     FontManager* fontMgr = [FontManager new];
  1059.     Font* newFont = [fontMgr convertFont:[fontMgr selFont]];
  1060.     if (newFont != 0 && newFont != font)
  1061.         {
  1062.         [window disableDisplay];
  1063.         Font* oldFont = font;
  1064.         [self setFont:newFont];
  1065.         if (delegate != 0 &&
  1066.             [delegate respondsTo: @selector(tableScroll:changeFont:to:)])
  1067.             [delegate tableScroll:self changeFont:oldFont to:newFont];
  1068.         if (dataDelegate != 0 &&
  1069.             [dataDelegate respondsTo: @selector(tableScroll:changeFont:to:)])
  1070.             [dataDelegate tableScroll:self changeFont:oldFont to:newFont];
  1071.         [window reenableDisplay];
  1072.         [self update];
  1073.         }
  1074.     return self;
  1075.     }
  1076.  
  1077.  
  1078. //-----------------------------------------------------------------------------
  1079. // COLOR
  1080. //
  1081. // The following macros expand into the implementations for these functions.
  1082. // Their names are listed so they can be found when searched for.
  1083. // setBackgroundColor:, setTextColor:,
  1084. // setHighlightBackgroundColor:, setHighlightTextColor:
  1085. // setBackgroundGray:, setTextGray:,
  1086. // setHighlightBackgroundGray:, setHighlightTextGray:
  1087. // backgroundGray:, textGray:, highlightBackgroundGray:, highlightTextGray:
  1088. //-----------------------------------------------------------------------------
  1089. + (NXColor) defaultBackgroundColor                { return NX_COLORLTGRAY; }
  1090. + (NXColor) defaultTextColor                    { return NX_COLORBLACK; }
  1091. + (NXColor) defaultHighlightBackgroundColor        { return NX_COLORWHITE; }
  1092. + (NXColor) defaultHighlightTextColor            { return NX_COLORBLACK; }
  1093.  
  1094. - (NXColor) backgroundColor                { return backgroundColor; }
  1095. - (NXColor) textColor                    { return textColor; }
  1096. - (NXColor) highlightBackgroundColor    { return highlightBackgroundColor; }
  1097. - (NXColor) highlightTextColor            { return highlightTextColor; }
  1098.  
  1099. - setColor:(NXColor) value        { return [self setBackgroundColor:value]; }
  1100. - (NXColor) color                { return [self backgroundColor]; }
  1101.  
  1102. - setColor:(NXColor)x            // New color value.
  1103.         var:(NXColor*)v            // Instance variable for the color.
  1104.         sel1:(SEL)sel1            // "setOwner...Color:" message for cell.
  1105.         sel2:(SEL)sel2            // "set...Color:" message for cell.
  1106.         notifySel:(SEL)notifySel        // "..ColorChangedTo:" message
  1107.     {
  1108.     if (!NXEqualColor( x, *v ))
  1109.         {
  1110.         BOOL const was_auto = [self isAutodisplay];
  1111.         [self setAutodisplay:NO];
  1112.  
  1113.         *v = x;
  1114.         if (v == &backgroundColor) [self forwardBGColor];
  1115.  
  1116.         if (![self isLazy])
  1117.             {
  1118.             int const NRows = num_rows;
  1119.             int const NCols = num_cols;
  1120.             for (int r = 0; r < NRows;    r++)
  1121.                 for (int c = 0;     c < NCols;     c++)
  1122.                     {
  1123.                     id cell = [self cellAt:r:c];
  1124.                     if (cell != 0)
  1125.                         {
  1126.                         if ([cell respondsTo:sel1])
  1127.                             (*[cell methodFor:sel1])( cell, sel1, x );
  1128.                         else if ([cell respondsTo:sel2])
  1129.                             (*[cell methodFor:sel2])( cell, sel2, x );
  1130.                         }
  1131.                     }
  1132.             }
  1133.  
  1134.         if (delegate != 0 && [delegate respondsTo:notifySel])
  1135.             (*[delegate methodFor:notifySel])( delegate, notifySel, self, x );
  1136.  
  1137.         if (dataDelegate != 0 && [dataDelegate respondsTo:notifySel])
  1138.             (*[dataDelegate methodFor:notifySel])
  1139.                         ( dataDelegate, notifySel, self, x );
  1140.  
  1141.         [self setNeedsDisplay:YES];
  1142.         [self setAutodisplay:was_auto];            // Will display if needed.
  1143.         }
  1144.  
  1145.     return self;
  1146.     }
  1147.  
  1148.  
  1149. #define MISC_SET_COLOR_FUNC(LNAME,CNAME)\
  1150. - set##CNAME##Color: (NXColor) value\
  1151.     { return [self setColor:value\
  1152.                 var:& LNAME##Color\
  1153.                 sel1:@selector(setOwner##CNAME##Color:)\
  1154.                 sel2:@selector(set##CNAME##Color:)\
  1155.                 notifySel:@selector(tableScroll:LNAME##ColorChangedTo:)]; }
  1156.  
  1157. MISC_SET_COLOR_FUNC( background, Background )
  1158. MISC_SET_COLOR_FUNC( text, Text )
  1159. MISC_SET_COLOR_FUNC( highlightBackground, HighlightBackground )
  1160. MISC_SET_COLOR_FUNC( highlightText, HighlightText )
  1161. #undef MISC_SET_COLOR_FUNC
  1162.  
  1163.  
  1164. static inline float color_to_gray( NXColor x )
  1165.     {
  1166.     float gray;
  1167.     NXConvertColorToGray( x, &gray );
  1168.     return gray;
  1169.     }
  1170.  
  1171.  
  1172. #define MISC_GET_GRAY_FUNC( LNAME )\
  1173. - (float) LNAME##Gray { return color_to_gray( [self LNAME##Color] ); }
  1174.  
  1175. MISC_GET_GRAY_FUNC( background )
  1176. MISC_GET_GRAY_FUNC( text )
  1177. MISC_GET_GRAY_FUNC( highlightBackground )
  1178. MISC_GET_GRAY_FUNC( highlightText )
  1179. #undef MISC_GET_GRAY_FUNC
  1180.  
  1181. #define MISC_SET_GRAY_FUNC( CNAME )\
  1182. - set##CNAME##Gray: (float) x\
  1183.     { return [self set##CNAME##Color: NXConvertGrayToColor(x)]; }
  1184.  
  1185. MISC_SET_GRAY_FUNC( Background )
  1186. MISC_SET_GRAY_FUNC( Text )
  1187. MISC_SET_GRAY_FUNC( HighlightBackground )
  1188. MISC_SET_GRAY_FUNC( HighlightText )
  1189. #undef MISC_SET_GRAY_FUNC
  1190.  
  1191.  
  1192. //-----------------------------------------------------------------------------
  1193. // SAVE / RESTORE
  1194. //-----------------------------------------------------------------------------
  1195.  
  1196. - border:(MiscBorderType)b slotOrder:(MiscIntList*)list
  1197.     {
  1198.     if (list != 0)
  1199.         {
  1200.         MiscTableBorder const* const bp = info[b]->border;
  1201.         MiscCoord_P const* const vmap = bp->getVMap();
  1202.         int const lim = bp->count();
  1203.         [list empty];
  1204.         for (int i = 0;     i < lim;  i++)
  1205.             [list addInt: (vmap ? vmap[i] : i) ];
  1206.         return self;
  1207.         }
  1208.     return 0;
  1209.     }
  1210. - colOrder:(MiscIntList*)list
  1211.     { return [self border:MISC_COL_BORDER slotOrder:list]; }
  1212. - rowOrder:(MiscIntList*)list
  1213.     { return [self border:MISC_ROW_BORDER slotOrder:list]; }
  1214.  
  1215. - border:(MiscBorderType)b setSlotOrder:(MiscIntList*)list
  1216.     {
  1217.     id retval = 0;
  1218.     if (list != 0)
  1219.         {
  1220.         MiscTableBorder* const bp = info[b]->border;
  1221.         int const lim = bp->count();
  1222.         if ([list count] == lim)
  1223.             if (bp->setVMap( [list rawData] ))
  1224.                 {
  1225.                 MiscBorderType const ob = otherBorder(b);
  1226.                 if ([self autoSortSlots:ob])
  1227.                     [self sortSlots:ob];
  1228.                 retval = self;
  1229.                 }
  1230.         }
  1231.     return retval;
  1232.     }
  1233. - setColOrder:(MiscIntList*)list
  1234.     { return [self border:MISC_COL_BORDER setSlotOrder:list]; }
  1235. - setRowOrder:(MiscIntList*)list
  1236.     { return [self border:MISC_ROW_BORDER setSlotOrder:list]; }
  1237.  
  1238. - (char*) border:(MiscBorderType)b slotOrderAsString:(char*)buff
  1239.         size:(int)buff_size canExpand:(BOOL)canExpand
  1240.     {
  1241.     char* retval;
  1242.     MiscIntList* list = [[MiscIntList alloc] init];
  1243.     [self border:b slotOrder:list];
  1244.     retval = [list writeToString:buff size:buff_size canExpand:canExpand];
  1245.     [list free];
  1246.     return retval;
  1247.     }
  1248. - (char*) colOrderAsString:(char*)buff
  1249.         size:(int)buff_size canExpand:(BOOL)canExpand
  1250.     { return [self border:MISC_COL_BORDER slotOrderAsString:buff
  1251.                         size:buff_size canExpand:canExpand]; }
  1252. - (char*) rowOrderAsString:(char*)buff
  1253.         size:(int)buff_size canExpand:(BOOL)canExpand
  1254.     { return [self border:MISC_ROW_BORDER slotOrderAsString:buff
  1255.                         size:buff_size canExpand:canExpand]; }
  1256.  
  1257. - border:(MiscBorderType)b setSlotOrderFromString:(char const*)s
  1258.     {
  1259.     id retval;
  1260.     MiscIntList* list = [[MiscIntList alloc] init];
  1261.     [list readFromString:s];
  1262.     retval = [self border:b setSlotOrder:list];
  1263.     [list free];
  1264.     return retval;
  1265.     }
  1266. - setColOrderFromString:(char const*)s
  1267.     { return [self border:MISC_COL_BORDER setSlotOrderFromString:s]; }
  1268. - setRowOrderFromString:(char const*)s
  1269.     { return [self border:MISC_ROW_BORDER setSlotOrderFromString:s]; }
  1270.  
  1271.  
  1272. - border:(MiscBorderType)b slotSizes:(MiscIntList*)list
  1273.     {
  1274.     if (list != 0)
  1275.         {
  1276.         MiscTableBorder const* const bp = info[b]->border;
  1277.         int const lim = bp->count();
  1278.         [list empty];
  1279.         for (int i = 0;     i < lim;  i++)
  1280.             [list addInt: (int) bp->getSize_P( i ) ];
  1281.         return self;
  1282.         }
  1283.     return 0;
  1284.     }
  1285. - colSizes:(MiscIntList*)list
  1286.     { return [self border:MISC_COL_BORDER slotSizes:list]; }
  1287. - rowSizes:(MiscIntList*)list
  1288.     { return [self border:MISC_ROW_BORDER slotSizes:list]; }
  1289.  
  1290. - border:(MiscBorderType)b setSlotSizes:(MiscIntList*)list
  1291.     {
  1292.     if (list != 0)
  1293.         {
  1294.         MiscTableBorder* const bp = info[b]->border;
  1295.         int const lim = bp->count();
  1296.         if ([list count] == lim)
  1297.             {
  1298.             for (int i = 0;     i < lim;  i++)
  1299.                 bp->setSize_P( i, (MiscPixels) [list intAt:i] );
  1300.             [self constrainSize];
  1301.             return self;
  1302.             }
  1303.         }
  1304.     return 0;
  1305.     }
  1306. - setColSizes:(MiscIntList*)list
  1307.     { return [self border:MISC_COL_BORDER setSlotSizes:list]; }
  1308. - setRowSizes:(MiscIntList*)list
  1309.     { return [self border:MISC_ROW_BORDER setSlotSizes:list]; }
  1310.  
  1311. - (char*) border:(MiscBorderType)b slotSizesAsString:(char*)buff
  1312.         size:(int)buff_size canExpand:(BOOL)canExpand
  1313.     {
  1314.     char* retval;
  1315.     MiscIntList* list = [[MiscIntList alloc] init];
  1316.     [self border:b slotSizes:list];
  1317.     retval = [list writeToString:buff size:buff_size canExpand:canExpand];
  1318.     [list free];
  1319.     return retval;
  1320.     }
  1321. - (char*) colSizesAsString:(char*)buff
  1322.         size:(int)buff_size canExpand:(BOOL)canExpand
  1323.     { return [self border:MISC_COL_BORDER slotSizesAsString:buff
  1324.                         size:buff_size canExpand:canExpand]; }
  1325. - (char*) rowSizesAsString:(char*)buff
  1326.         size:(int)buff_size canExpand:(BOOL)canExpand
  1327.     { return [self border:MISC_ROW_BORDER slotSizesAsString:buff
  1328.                         size:buff_size canExpand:canExpand]; }
  1329.  
  1330. - border:(MiscBorderType)b setSlotSizesFromString:(char const*)s
  1331.     {
  1332.     id retval;
  1333.     MiscIntList* list = [[MiscIntList alloc] init];
  1334.     [list readFromString:s];
  1335.     retval = [self border:b setSlotSizes:list];
  1336.     [list free];
  1337.     return retval;
  1338.     }
  1339. - setColSizesFromString:(char const*)s
  1340.     { return [self border:MISC_COL_BORDER setSlotSizesFromString:s]; }
  1341. - setRowSizesFromString:(char const*)s
  1342.     { return [self border:MISC_ROW_BORDER setSlotSizesFromString:s]; }
  1343.  
  1344.  
  1345.  
  1346. //-----------------------------------------------------------------------------
  1347. // Border Views
  1348. //-----------------------------------------------------------------------------
  1349. - (BOOL) setBorder:(MiscBorderType)type on:(BOOL)on
  1350.     {
  1351.     MiscBorderInfo& b = *(info[type]);
  1352.     if (b.isOn != on)
  1353.         {
  1354.         BOOL const other_border_is_on = info[otherBorder(type)]->isOn;
  1355.         b.isOn = on;
  1356.         if (on)
  1357.             {
  1358.             [self addSubview: b.clip];
  1359.             [window invalidateCursorRectsForView: b.view];
  1360.             if (other_border_is_on)
  1361.                 [self addSubview: nullView];
  1362.             }
  1363.         else
  1364.             {
  1365.             [b.clip removeFromSuperview];
  1366.             if (other_border_is_on)
  1367.                 [nullView removeFromSuperview];
  1368.             }
  1369.         [self tile];
  1370.         [self constrainSize];
  1371.         [self update];
  1372.         return YES;
  1373.         }
  1374.     return NO;
  1375.     }
  1376.  
  1377.  
  1378. //-----------------------------------------------------------------------------
  1379. // SLOT methods
  1380. //-----------------------------------------------------------------------------
  1381. - (MiscTableBorder*) border:(MiscBorderType)b
  1382.         { return info[b]->border; }
  1383. - (BOOL) border:(MiscBorderType)b setTitlesOn: (BOOL) on_off
  1384.         { return [self setBorder:b on:on_off]; }
  1385. - (BOOL) borderTitlesOn:(MiscBorderType)b
  1386.         { return info[b]->isOn; }
  1387. - (MiscTableTitleMode) borderTitleMode:(MiscBorderType)b
  1388.         { return info[b]->border->getTitleMode(); }
  1389. - (void) border:(MiscBorderType)b setTitleMode:(MiscTableTitleMode)x
  1390.         {
  1391.         MiscBorderInfo* const ip = info[b];
  1392.         if (ip->border->setTitleMode(x) && ip->isOn && ip->border->count() > 0)
  1393.             [ip->view update];
  1394.         }
  1395.  
  1396. - border:(MiscBorderType)b moveSlotFrom:(int)fromPos to:(int)toPos
  1397.         { info[b]->border->moveFromTo(fromPos,toPos); return self; }
  1398. - (int) border:(MiscBorderType)b slotPosition:(int)n
  1399.         { return info[b]->border->physicalToVisual(n); }
  1400. - (int) border:(MiscBorderType)b slotAtPosition:(int)n
  1401.         { return info[b]->border->visualToPhysical(n); }
  1402.  
  1403. - (void) border:(MiscBorderType)b physicalToVisual:(MiscIntList*)list
  1404.         {
  1405.         for (unsigned int i = [list count];     i-- > 0; )
  1406.             {
  1407.             MiscCoord_P const p = [list intAt:i];
  1408.             [list replaceIntAt:i with:[self border:b slotPosition:p]];
  1409.             }
  1410.         }
  1411.  
  1412. - (void) border:(MiscBorderType)b visualToPhysical:(MiscIntList*)list
  1413.         {
  1414.         for (unsigned int i = [list count];     i-- > 0; )
  1415.             {
  1416.             MiscCoord_V const v = [list intAt:i];
  1417.             [list replaceIntAt:i with:[self border:b slotAtPosition:v]];
  1418.             }
  1419.         }
  1420.  
  1421.  
  1422. - (BOOL) sizeableSlots:(MiscBorderType)b
  1423.         { return info[b]->border->isSizeable(); }
  1424. - (BOOL) draggableSlots:(MiscBorderType)b
  1425.         { return info[b]->border->isDraggable(); }
  1426. - (BOOL) modifierDragSlots:(MiscBorderType)b
  1427.         { return info[b]->border->isModifierDrag(); }
  1428. - (NXCoord) uniformSizeSlots:(MiscBorderType)b
  1429.         { return (NXCoord) info[b]->border->getUniformSize(); }
  1430.  
  1431. - (NXCoord) border:(MiscBorderType)b slotAdjustedSize:(int)n
  1432.         { return (NXCoord) info[b]->border->effectiveSize_P(n); }
  1433. - (NXCoord) border:(MiscBorderType)b slotSize:(int)n
  1434.         { return (NXCoord) info[b]->border->getSize_P(n); }
  1435. - (NXCoord) border:(MiscBorderType)b slotMinSize:(int)n
  1436.         { return (NXCoord) info[b]->border->getMinSize_P(n); }
  1437. - (NXCoord) border:(MiscBorderType)b slotMaxSize:(int)n
  1438.         { return (NXCoord) info[b]->border->getMaxSize_P(n); }
  1439. - (NXCoord) border:(MiscBorderType)b slotDataSize:(int)n
  1440.         { return (NXCoord) info[b]->border->getDataSize_P(n); }
  1441. - (BOOL) border:(MiscBorderType)b slotIsSizeable:(int)n
  1442.         { return info[b]->border->isSizeable_P(n); }
  1443. - (BOOL) border:(MiscBorderType)b slotExpandsToData:(int)n
  1444.         { return info[b]->border->isData_P(n); }
  1445. - (BOOL) border:(MiscBorderType)b slotIsAutosize:(int)n
  1446.         { return info[b]->border->isSpringy_P(n); }
  1447. - (char const*) border:(MiscBorderType)b slotTitle:(int)n
  1448.         { return info[b]->border->getTitle_P(n); }
  1449. - (int) border:(MiscBorderType)b slotTag:(int)n
  1450.         { return info[b]->border->getTag_P(n); }
  1451. - (MiscTableCellStyle) border:(MiscBorderType)b slotCellType:(int)n
  1452.         { return info[b]->border->getStyle_P(n); }
  1453. - border:(MiscBorderType)b slotCellPrototype:(int)n
  1454.         { return info[b]->border->getPrototype_P(n); }
  1455.  
  1456. - (void) border:(MiscBorderType)b setSizeableSlots:(BOOL)flag
  1457.         { info[b]->border->setSizeable(flag); }
  1458. - (void) border:(MiscBorderType)b setDraggableSlots:(BOOL)flag
  1459.         { info[b]->border->setDraggable(flag); }
  1460. - (void) border:(MiscBorderType)b setModifierDragSlots:(BOOL)flag
  1461.         { info[b]->border->setModifierDrag(flag); }
  1462. - (void) border:(MiscBorderType)b setUniformSizeSlots:(NXCoord)uniform_size
  1463.         {
  1464.         MiscBorderInfo* const ip = info[b];
  1465.         if (ip->border->setUniformSize((MiscPixels)floor(uniform_size)))
  1466.             {
  1467.             [self constrainSize];
  1468.             if (b == MISC_ROW_BORDER)
  1469.                 {
  1470.                 [self setLineScroll:uniform_size];
  1471.                 [self setPageScroll:uniform_size];
  1472.                 }
  1473.             [self update];
  1474.             }
  1475.         }
  1476.  
  1477. - (void) border:(MiscBorderType)b setSlot:(int)n size:(NXCoord)size
  1478.         {
  1479.         info[b]->border->setSize_P( n, (MiscPixels)floor(size) );
  1480.         [self constrainSize];
  1481.         }
  1482. - (void) border:(MiscBorderType)b setSlot:(int)n minSize:(NXCoord)size
  1483.         {
  1484.         info[b]->border->setMinSize_P( n, (MiscPixels)floor(size) );
  1485.         [self constrainSize];
  1486.         }
  1487. - (void) border:(MiscBorderType)b setSlot:(int)n maxSize:(NXCoord)size
  1488.         {
  1489.         info[b]->border->setMaxSize_P( n, (MiscPixels)floor(size) );
  1490.         [self constrainSize];
  1491.         }
  1492. - (void) border:(MiscBorderType)b setSlot:(int)n dataSize:(NXCoord)size
  1493.         { info[b]->border->setDataSize_P( n, (MiscPixels)floor(size) ); }
  1494. - (void) border:(MiscBorderType)b setSlot:(int)n sizeable:(BOOL)flag
  1495.         { info[b]->border->setSizeable_P( n, flag ); }
  1496. - (void) border:(MiscBorderType)b setSlot:(int)n expandsToData:(BOOL)flag
  1497.         { info[b]->border->setData_P( n, flag ); }
  1498. - (void) border:(MiscBorderType)b setSlot:(int)n autosize:(BOOL)flag
  1499.         {
  1500.         info[b]->border->setSpringy_P( n, flag );
  1501.         [self constrainSize];
  1502.         }
  1503.  
  1504. - (void) border:(MiscBorderType)b setSlot:(int)n title:(char const*)title
  1505.         {
  1506.         MiscBorderInfo* const ip = info[b];
  1507.         if (ip->border->setTitle_P( n, title ) && ip->isOn)
  1508.             [self border:b drawSlotTitle:n];
  1509.         }
  1510.  
  1511. - (void) border:(MiscBorderType)b setSlot:(int)n tag:(int)x
  1512.         { info[b]->border->setTag_P( n, x ); }
  1513. - (void) border:(MiscBorderType)b setSlot:(int)n
  1514.                 cellType:(MiscTableCellStyle)type
  1515.         { info[b]->border->setStyle_P(n,type); }
  1516. - (void) border:(MiscBorderType)b setSlot:(int)n cellPrototype:p
  1517.         { info[b]->border->setPrototype_P(n,p); }
  1518.  
  1519.  
  1520.  
  1521. //-----------------------------------------------------------------------------
  1522. // COL methods
  1523. //-----------------------------------------------------------------------------
  1524. - (MiscTableBorder*) colBorder
  1525.         { return colInfo.border; }
  1526. - (BOOL) colTitlesOn
  1527.         { return [self borderTitlesOn:MISC_COL_BORDER]; }
  1528. - (BOOL) setColTitlesOn:(BOOL)x
  1529.         { return [self setBorder:MISC_COL_BORDER on:x]; }
  1530. - (MiscTableTitleMode) colTitleMode
  1531.         { return [self borderTitleMode:MISC_COL_BORDER]; }
  1532. - (void) setColTitleMode:(MiscTableTitleMode)x
  1533.         { [self border:MISC_COL_BORDER setTitleMode:x]; }
  1534.  
  1535. - moveColFrom:(int)fromPos to:(int)toPos
  1536.         { return [self border:MISC_COL_BORDER moveSlotFrom:fromPos to:toPos]; }
  1537. - (int) colPosition:(int)n
  1538.         { return [self border:MISC_COL_BORDER slotPosition:n]; }
  1539. - (int) colAtPosition:(int)n
  1540.         { return [self border:MISC_COL_BORDER slotAtPosition:n]; }
  1541.  
  1542. - (BOOL) sizeableCols
  1543.         { return [self sizeableSlots:MISC_COL_BORDER]; }
  1544. - (BOOL) draggableCols
  1545.         { return [self draggableSlots:MISC_COL_BORDER]; }
  1546. - (BOOL) modifierDragCols
  1547.         { return [self modifierDragSlots:MISC_COL_BORDER]; }
  1548. - (NXCoord) uniformSizeCols
  1549.         { return [self uniformSizeSlots:MISC_COL_BORDER]; }
  1550.  
  1551. - (NXCoord) colAdjustedSize:(int)n
  1552.         { return [self border:MISC_COL_BORDER slotAdjustedSize:n]; }
  1553. - (NXCoord) colSize:(int)n
  1554.         { return [self border:MISC_COL_BORDER slotSize:n]; }
  1555. - (NXCoord) colMinSize:(int)n
  1556.         { return [self border:MISC_COL_BORDER slotMinSize:n]; }
  1557. - (NXCoord) colMaxSize:(int)n
  1558.         { return [self border:MISC_COL_BORDER slotMaxSize:n]; }
  1559. - (NXCoord) colDataSize:(int)n
  1560.         { return [self border:MISC_COL_BORDER slotDataSize:n]; }
  1561. - (BOOL) colIsSizeable:(int)n
  1562.         { return [self border:MISC_COL_BORDER slotIsSizeable:n]; }
  1563. - (BOOL) colExpandsToData:(int)n
  1564.         { return [self border:MISC_COL_BORDER slotExpandsToData:n]; }
  1565. - (BOOL) colIsAutosize:(int)n
  1566.         { return [self border:MISC_COL_BORDER slotIsAutosize:n]; }
  1567. - (char const*) colTitle:(int)n
  1568.         { return [self border:MISC_COL_BORDER slotTitle:n]; }
  1569. - (int) colTag:(int)n
  1570.         { return [self border:MISC_COL_BORDER slotTag:n]; }
  1571. - (MiscTableCellStyle) colCellType:(int)n
  1572.         { return [self border:MISC_COL_BORDER slotCellType:n]; }
  1573. - colCellPrototype:(int)n
  1574.         { return [self border:MISC_COL_BORDER slotCellPrototype:n]; }
  1575.  
  1576. - (void) setSizeableCols:(BOOL)flag
  1577.         { [self border:MISC_COL_BORDER setSizeableSlots:flag]; }
  1578. - (void) setDraggableCols:(BOOL)flag
  1579.         { [self border:MISC_COL_BORDER setDraggableSlots:flag]; }
  1580. - (void) setModifierDragCols:(BOOL)flag
  1581.         { [self border:MISC_COL_BORDER setModifierDragSlots:flag]; }
  1582. - (void) setUniformSizeCols:(NXCoord)size
  1583.         { [self border:MISC_COL_BORDER setUniformSizeSlots:size]; }
  1584.  
  1585. - (void) setCol:(int)n size:(NXCoord)size
  1586.         { [self border:MISC_COL_BORDER setSlot:n size:size]; }
  1587. - (void) setCol:(int)n minSize:(NXCoord)size
  1588.         { [self border:MISC_COL_BORDER setSlot:n minSize:size]; }
  1589. - (void) setCol:(int)n maxSize:(NXCoord)size
  1590.         { [self border:MISC_COL_BORDER setSlot:n maxSize:size]; }
  1591. - (void) setCol:(int)n dataSize:(NXCoord)size
  1592.         { [self border:MISC_COL_BORDER setSlot:n dataSize:size]; }
  1593. - (void) setCol:(int)n sizeable:(BOOL)flag
  1594.         { [self border:MISC_COL_BORDER setSlot:n sizeable:flag]; }
  1595. - (void) setCol:(int)n expandsToData:(BOOL)flag
  1596.         { [self border:MISC_COL_BORDER setSlot:n expandsToData:flag]; }
  1597. - (void) setCol:(int)n autosize:(BOOL)flag
  1598.         { [self border:MISC_COL_BORDER setSlot:n autosize:flag]; }
  1599. - (void) setCol:(int)n title:(char const*)title
  1600.         { [self border:MISC_COL_BORDER setSlot:n title:title]; }
  1601. - (void) setCol:(int)n tag:(int)x
  1602.         { [self border:MISC_COL_BORDER setSlot:n tag:x]; }
  1603. - (void) setCol:(int)n cellType:(MiscTableCellStyle)x
  1604.         { [self border:MISC_COL_BORDER setSlot:n cellType:x]; }
  1605. - (void) setCol:(int)n cellPrototype:p
  1606.         { [self border:MISC_COL_BORDER setSlot:n cellPrototype:p]; }
  1607.  
  1608.  
  1609. //-----------------------------------------------------------------------------
  1610. // ROW methods
  1611. //-----------------------------------------------------------------------------
  1612. - (MiscTableBorder*) rowBorder
  1613.         { return rowInfo.border; }
  1614. - (BOOL) rowTitlesOn
  1615.         { return [self borderTitlesOn:MISC_ROW_BORDER]; }
  1616. - (BOOL) setRowTitlesOn:(BOOL)x
  1617.         { return [self setBorder:MISC_ROW_BORDER on:x]; }
  1618. - (MiscTableTitleMode) rowTitleMode
  1619.         { return [self borderTitleMode:MISC_ROW_BORDER]; }
  1620. - (void) setRowTitleMode:(MiscTableTitleMode)x
  1621.         { [self border:MISC_ROW_BORDER setTitleMode:x]; }
  1622.  
  1623. - moveRowFrom:(int)fromPos to:(int)toPos
  1624.         { return [self border:MISC_ROW_BORDER moveSlotFrom:fromPos to:toPos]; }
  1625. - (int) rowPosition:(int)n
  1626.         { return [self border:MISC_ROW_BORDER slotPosition:n]; }
  1627. - (int) rowAtPosition:(int)n
  1628.         { return [self border:MISC_ROW_BORDER slotAtPosition:n]; }
  1629.  
  1630. - (BOOL) sizeableRows
  1631.         { return [self sizeableSlots:MISC_ROW_BORDER]; }
  1632. - (BOOL) draggableRows
  1633.         { return [self draggableSlots:MISC_ROW_BORDER]; }
  1634. - (BOOL) modifierDragRows
  1635.         { return [self modifierDragSlots:MISC_ROW_BORDER]; }
  1636. - (NXCoord) uniformSizeRows
  1637.         { return [self uniformSizeSlots:MISC_ROW_BORDER]; }
  1638.  
  1639. - (NXCoord) rowAdjustedSize:(int)n
  1640.         { return [self border:MISC_ROW_BORDER slotAdjustedSize:n]; }
  1641. - (NXCoord) rowSize:(int)n
  1642.         { return [self border:MISC_ROW_BORDER slotSize:n]; }
  1643. - (NXCoord) rowMinSize:(int)n
  1644.         { return [self border:MISC_ROW_BORDER slotMinSize:n]; }
  1645. - (NXCoord) rowMaxSize:(int)n
  1646.         { return [self border:MISC_ROW_BORDER slotMaxSize:n]; }
  1647. - (NXCoord) rowDataSize:(int)n
  1648.         { return [self border:MISC_ROW_BORDER slotDataSize:n]; }
  1649. - (BOOL) rowIsSizeable:(int)n
  1650.         { return [self border:MISC_ROW_BORDER slotIsSizeable:n]; }
  1651. - (BOOL) rowExpandsToData:(int)n
  1652.         { return [self border:MISC_ROW_BORDER slotExpandsToData:n]; }
  1653. - (BOOL) rowIsAutosize:(int)n
  1654.         { return [self border:MISC_ROW_BORDER slotIsAutosize:n]; }
  1655. - (char const*) rowTitle:(int)n
  1656.         { return [self border:MISC_ROW_BORDER slotTitle:n]; }
  1657. - (int) rowTag:(int)n
  1658.         { return [self border:MISC_ROW_BORDER slotTag:n]; }
  1659. - (MiscTableCellStyle) rowCellType:(int)n
  1660.         { return [self border:MISC_ROW_BORDER slotCellType:n]; }
  1661. - rowCellPrototype:(int)n
  1662.         { return [self border:MISC_ROW_BORDER slotCellPrototype:n]; }
  1663.  
  1664. - (void) setSizeableRows:(BOOL)flag
  1665.         { [self border:MISC_ROW_BORDER setSizeableSlots:flag]; }
  1666. - (void) setDraggableRows:(BOOL)flag
  1667.         { [self border:MISC_ROW_BORDER setDraggableSlots:flag]; }
  1668. - (void) setModifierDragRows:(BOOL)flag
  1669.         { [self border:MISC_ROW_BORDER setModifierDragSlots:flag]; }
  1670. - (void) setUniformSizeRows:(NXCoord)size
  1671.         { [self border:MISC_ROW_BORDER setUniformSizeSlots:size]; }
  1672.  
  1673. - (void) setRow:(int)n size:(NXCoord)size
  1674.         { [self border:MISC_ROW_BORDER setSlot:n size:size]; }
  1675. - (void) setRow:(int)n minSize:(NXCoord)size
  1676.         { [self border:MISC_ROW_BORDER setSlot:n minSize:size]; }
  1677. - (void) setRow:(int)n maxSize:(NXCoord)size
  1678.         { [self border:MISC_ROW_BORDER setSlot:n maxSize:size]; }
  1679. - (void) setRow:(int)n dataSize:(NXCoord)size
  1680.         { [self border:MISC_ROW_BORDER setSlot:n dataSize:size]; }
  1681. - (void) setRow:(int)n sizeable:(BOOL)flag
  1682.         { [self border:MISC_ROW_BORDER setSlot:n sizeable:flag]; }
  1683. - (void) setRow:(int)n expandsToData:(BOOL)flag
  1684.         { [self border:MISC_ROW_BORDER setSlot:n expandsToData:flag]; }
  1685. - (void) setRow:(int)n autosize:(BOOL)flag
  1686.         { [self border:MISC_ROW_BORDER setSlot:n autosize:flag]; }
  1687. - (void) setRow:(int)n title:(char const*)title
  1688.         { [self border:MISC_ROW_BORDER setSlot:n title:title]; }
  1689. - (void) setRow:(int)n tag:(int)x
  1690.         { [self border:MISC_ROW_BORDER setSlot:n tag:x]; }
  1691. - (void) setRow:(int)n cellType:(MiscTableCellStyle)x
  1692.         { [self border:MISC_ROW_BORDER setSlot:n cellType:x]; }
  1693. - (void) setRow:(int)n cellPrototype:p
  1694.         { [self border:MISC_ROW_BORDER setSlot:n cellPrototype:p]; }
  1695.  
  1696. //-----------------------------------------------------------------------------
  1697. // - read:selector:
  1698. //-----------------------------------------------------------------------------
  1699. - (SEL) read:(int)ver selector:(NXTypedStream*)stream
  1700.     {
  1701.     SEL cmd = 0;
  1702.     char* str;
  1703.     NXReadType( stream, @encode(char*), &str );
  1704.     if (str != 0)
  1705.         {
  1706.         if (*str != '\0')
  1707.             cmd = sel_getUid( str );
  1708.         free( str );
  1709.         }
  1710.     return cmd;
  1711.     }
  1712.  
  1713.  
  1714. //-----------------------------------------------------------------------------
  1715. // - read:globalInfo:
  1716. //
  1717. //        NOTE: Cannot archive sort_entry_func and sort_slot_func because they 
  1718. //                are function addresses.     
  1719. //-----------------------------------------------------------------------------
  1720. - (void) read:(int)ver globalInfo:(NXTypedStream*)stream
  1721.     {
  1722.     NXReadType( stream, @encode(int), &tag );
  1723.     NXReadType( stream, @encode(BOOL), &enabled );
  1724.     NXReadType( stream, @encode(BOOL), &lazy );
  1725.     NXReadType( stream, @encode(MiscSelectionMode), &mode );
  1726.     font = NXReadObject( stream );
  1727.     textColor = NXReadColor( stream );
  1728.     backgroundColor = NXReadColor( stream );
  1729.     highlightTextColor = NXReadColor( stream );
  1730.     highlightBackgroundColor = NXReadColor( stream );
  1731.     nextText    = NXReadObject( stream );
  1732.     previousText= NXReadObject( stream );
  1733.     delegate    = NXReadObject( stream );
  1734.     dataDelegate= NXReadObject( stream );
  1735.     target        = NXReadObject( stream );
  1736.     doubleTarget= NXReadObject( stream );
  1737.     action = [self read:ver selector:stream];
  1738.     doubleAction = [self read:ver selector:stream];
  1739.     }
  1740.  
  1741.  
  1742. //-----------------------------------------------------------------------------
  1743. // - read:border:stream:
  1744. //-----------------------------------------------------------------------------
  1745. - (void) read:(int)ver border:(MiscBorderInfo*)p stream:(NXTypedStream*)stream
  1746.     {
  1747.     NXZone* const z = [self zone];
  1748.     int n;
  1749.     if (p->sort_vector != 0)
  1750.         NXZoneFree( z, p->sort_vector );
  1751.     NXReadType( stream, @encode(int), &(n) );
  1752.     if (n > 0)
  1753.         {
  1754.         p->sort_vector_len = n;
  1755.         p->sort_vector = (int*) NXZoneMalloc( z, n * sizeof(int) );
  1756.         for (int i = 0;     i < n;     i++)
  1757.             NXReadType( stream, @encode(int), &(p->sort_vector[i]) );
  1758.         }
  1759.     else
  1760.         {
  1761.         p->sort_vector_len = 0;
  1762.         p->sort_vector = 0;
  1763.         }
  1764.     NXReadType( stream, @encode(BOOL), &(p->isOn) );
  1765.     NXReadType( stream, @encode(BOOL), &(p->autoSort) );
  1766.     NXReadType( stream, @encode(BOOL), &(p->constrain_min) );
  1767.     NXReadType( stream, @encode(BOOL), &(p->constrain_max) );
  1768.     if (p->border == 0)
  1769.         p->border = new( NXZoneMalloc( z, sizeof(*(p->border)) ) )
  1770.                         MiscTableBorder( MISC_ROW_BORDER );
  1771.     p->border->read( stream );    // FIXME: Should send ver.
  1772.     }
  1773.  
  1774.  
  1775. //-----------------------------------------------------------------------------
  1776. // - read:cells:
  1777. //
  1778. // FIXME: What happens when a non-empty non-lazy TableScroll reads the data
  1779. // from a lazy, empty one.    Does the memory get freed?
  1780. //-----------------------------------------------------------------------------
  1781. - (void) read:(int)ver cells: (NXTypedStream*) stream
  1782.     {
  1783.     NXReadType( stream, @encode(int), &num_cols );
  1784.     NXReadType( stream, @encode(int), &num_rows );
  1785.     max_rows = num_rows;
  1786.     if (lazy)
  1787.         {
  1788.         max_cells = 0;
  1789.         cells = 0;
  1790.         }
  1791.     else // (!lazy)
  1792.         {
  1793.         max_cells = max_rows * num_cols;
  1794.         if (max_cells == 0)
  1795.             cells = 0;
  1796.         else
  1797.             {
  1798.             int const nbytes = max_cells * sizeof(*cells);
  1799.             cells = (id*) NXZoneMalloc( [self zone], nbytes );
  1800.             id* p = cells;
  1801.             for (int r = 0;         r < num_rows;    r++)
  1802.                 for (int c = 0;     c < num_cols;    c++)
  1803.                     *p++ = NXReadObject( stream );
  1804.             }
  1805.         }
  1806.     }
  1807.  
  1808.  
  1809. //-----------------------------------------------------------------------------
  1810. // - read:
  1811. //-----------------------------------------------------------------------------
  1812. - read: (NXTypedStream*) stream
  1813.     {
  1814.     [super read:stream];
  1815.     char const* class_name = [[MiscTableScroll class] name];
  1816.     int ver = NXTypedStreamClassVersion( stream, class_name );
  1817.     if (((unsigned int)ver) > ((unsigned int)MISC_TS_VERSION))
  1818.         [self error:"%s: old library (version %d), can't -read: "
  1819.                         "new object (version %d).\n",
  1820.                         class_name,
  1821.                         MISC_TS_VERSION, ver ];
  1822.     [self read:ver globalInfo:stream];
  1823.     [self read:ver border:&colInfo stream:stream];
  1824.     [self read:ver border:&rowInfo stream:stream];
  1825.     [self read:ver cells:stream];
  1826.     [self doInit:ver];
  1827.     return self;
  1828.     }
  1829.  
  1830.  
  1831. //-----------------------------------------------------------------------------
  1832. // - writeSelector:stream:
  1833. //-----------------------------------------------------------------------------
  1834. - (void) writeSelector: (SEL) cmd stream: (NXTypedStream*) stream
  1835.     {
  1836.     char const* str = 0;
  1837.     if (cmd != 0)
  1838.         str = sel_getName( cmd );
  1839.     if (str == 0)                        // not an 'else if'
  1840.         str = "";
  1841.     NXWriteType( stream, @encode(char*), &str );
  1842.     }
  1843.  
  1844.  
  1845. //-----------------------------------------------------------------------------
  1846. // - writeGlobalInfo:
  1847. //
  1848. //        NOTE: Cannot archive sort_entry_func and sort_slot_func because they 
  1849. //                are function addresses.     
  1850. //-----------------------------------------------------------------------------
  1851. - (void) writeGlobalInfo: (NXTypedStream*) stream
  1852.     {
  1853.     NXWriteType( stream, @encode(int), &tag );
  1854.     NXWriteType( stream, @encode(BOOL), &enabled );
  1855.     NXWriteType( stream, @encode(BOOL), &lazy );
  1856.     NXWriteType( stream, @encode(MiscSelectionMode), &mode );
  1857.     NXWriteObject( stream, font );
  1858.     NXWriteColor( stream, textColor );
  1859.     NXWriteColor( stream, backgroundColor );
  1860.     NXWriteColor( stream, highlightTextColor );
  1861.     NXWriteColor( stream, highlightBackgroundColor );
  1862.     NXWriteObjectReference( stream, nextText );
  1863.     NXWriteObjectReference( stream, previousText );
  1864.     NXWriteObjectReference( stream, delegate );
  1865.     NXWriteObjectReference( stream, dataDelegate );
  1866.     NXWriteObjectReference( stream, target );
  1867.     NXWriteObjectReference( stream, doubleTarget );
  1868.     [self writeSelector: action stream: stream];
  1869.     [self writeSelector: doubleAction stream: stream];
  1870.     }
  1871.  
  1872.  
  1873. //-----------------------------------------------------------------------------
  1874. // - writeBorder:stream:
  1875. //-----------------------------------------------------------------------------
  1876. - (void) writeBorder:(MiscBorderInfo*)p stream:(NXTypedStream*)stream
  1877.     {
  1878.     int const n = p->sort_vector_len;
  1879.     NXWriteType( stream, @encode(int), &(n) );
  1880.     if (n > 0)
  1881.         for (int i = 0;     i < n;     i++)
  1882.             NXWriteType( stream, @encode(int), &(p->sort_vector[i]) );
  1883.     NXWriteType( stream, @encode(BOOL), &(p->isOn) );
  1884.     NXWriteType( stream, @encode(BOOL), &(p->autoSort) );
  1885.     NXWriteType( stream, @encode(BOOL), &(p->constrain_min) );
  1886.     NXWriteType( stream, @encode(BOOL), &(p->constrain_max) );
  1887.     p->border->write( stream );
  1888.     }
  1889.  
  1890.  
  1891. //-----------------------------------------------------------------------------
  1892. // - writeCells:
  1893. //-----------------------------------------------------------------------------
  1894. - (void) writeCells: (NXTypedStream*) stream
  1895.     {
  1896.     NXWriteType( stream, @encode(int), &num_cols );
  1897.     NXWriteType( stream, @encode(int), &num_rows );
  1898.     if (!lazy)
  1899.         for (int r = 0;     r < num_rows;    r++)
  1900.             for (int c = 0;     c < num_cols;    c++)
  1901.                 NXWriteObject( stream, [self cellAt:r:c] );
  1902.     }
  1903.  
  1904.  
  1905. //-----------------------------------------------------------------------------
  1906. // - write:
  1907. //-----------------------------------------------------------------------------
  1908. - write: (NXTypedStream*) stream
  1909.     {
  1910.     // Ensure that subviews are NOT archived.
  1911.     if (colInfo.isOn)    [colInfo.clip removeFromSuperview];
  1912.     if (rowInfo.isOn)    [rowInfo.clip removeFromSuperview];
  1913.     if (rowInfo.isOn && colInfo.isOn) [nullView removeFromSuperview];
  1914.     [tableView removeFromSuperview];
  1915.  
  1916.     [super write:stream];
  1917.     [self writeGlobalInfo:stream];
  1918.     [self writeBorder:&colInfo stream:stream];
  1919.     [self writeBorder:&rowInfo stream:stream];
  1920.     [self writeCells:stream];
  1921.  
  1922.     // Restore state.
  1923.     [self setDocView: tableView];
  1924.     if (colInfo.isOn)    [self addSubview:colInfo.clip];
  1925.     if (rowInfo.isOn)    [self addSubview:rowInfo.clip];
  1926.     if (rowInfo.isOn && colInfo.isOn) [self addSubview:nullView];
  1927.     return self;
  1928.     }
  1929.  
  1930.  
  1931. //-----------------------------------------------------------------------------
  1932. // DRAWING
  1933. //-----------------------------------------------------------------------------
  1934.  
  1935. - drawCellAt:(int)row :(int)col
  1936.     {
  1937.     [tableView drawCellAt:row:col];
  1938.     [window flushWindow];
  1939.     return self;
  1940.     }
  1941. - drawRow:(int)row
  1942.     {
  1943.     [tableView drawRow:row];
  1944.     [window flushWindow];
  1945.     return self;
  1946.     }
  1947. - drawCol:(int)col
  1948.     {
  1949.     [tableView drawCol:col];
  1950.     [window flushWindow];
  1951.     return self;
  1952.     }
  1953. - border:(MiscBorderType)b drawSlot:(int)n
  1954.     { return (b == MISC_COL_BORDER) ? [self drawCol:n] : [self drawRow:n]; }
  1955.  
  1956. - border:(MiscBorderType)b drawSlotTitle:(int)n            // physical position.
  1957.     {
  1958.     MiscBorderInfo* const ip = info[b];
  1959.     if (ip->isOn)                                        // visual position.
  1960.         {
  1961.         [ip->view drawSlot: [self border:b slotPosition:n]];
  1962.         [window flushWindow];
  1963.         }
  1964.     return self;
  1965.     }
  1966. - drawRowTitle:(int)n { return [self border:MISC_ROW_BORDER drawSlotTitle:n]; }
  1967. - drawColTitle:(int)n { return [self border:MISC_COL_BORDER drawSlotTitle:n]; }
  1968.  
  1969. - (void) reflectSelection
  1970.     {
  1971.     if ([self canDraw])
  1972.         {
  1973.         [window disableFlushWindow];
  1974.         [rowInfo.view reflectSelection];
  1975.         [colInfo.view reflectSelection];
  1976.         [tableView reflectSelection];
  1977.         [[window reenableFlushWindow] flushWindow];
  1978.         }
  1979.     else
  1980.         [self setNeedsDisplay:YES];
  1981.     }
  1982.  
  1983. - setAutodisplay:(BOOL) x
  1984.     {
  1985.     [rowInfo.view setAutodisplay:x];
  1986.     [colInfo.view setAutodisplay:x];
  1987.     [tableView setAutodisplay:x];
  1988.     return [super setAutodisplay:x];
  1989.     }
  1990.  
  1991. - (void) scrollCellToVisible: (int)row : (int) col
  1992.         { [tableView scrollCellToVisible: row:col]; }
  1993. - (void) scrollRowToVisible: (int)row { [tableView scrollRowToVisible:row]; }
  1994. - (void) scrollColToVisible: (int)col { [tableView scrollColToVisible:col]; }
  1995. - scrollSelToVisible
  1996.     {
  1997.     if ([self hasRowSelection])
  1998.         [self scrollRowToVisible: [self selectedRow]];
  1999.     else if ([self hasColSelection])
  2000.         [self scrollColToVisible: [self selectedCol]];
  2001.     return self;
  2002.     }
  2003.  
  2004.  
  2005. //-----------------------------------------------------------------------------
  2006. // MOUSE & KEYBOARD TRACKING
  2007. //-----------------------------------------------------------------------------
  2008. - (void) trackBy: (MiscBorderType)b { [tableView trackBy:b]; }
  2009. - (MiscBorderType) trackingBy { return [tableView trackingBy]; }
  2010.  
  2011. @end
  2012.